/*
 * HeadNode.h
 *
 * Part of libai/NNlib
 *
 * (c) 2008 Benjamin Russell, Matthew Russell
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#ifndef HEADNODE_H_
#define HEADNODE_H_

#include <vector>

template <class T>
class HeadNode
{
public:
    HeadNode();
    virtual ~HeadNode();

    virtual void Add_Input(T in_Input, T in_Weight);
    virtual void Remove_Input(unsigned int N);

    void Set_Threshold_Func(bool (*in_p_Threshold_Func)(HeadNode<T>*));

    void Set_Weight(unsigned int N, T in_Weight);
    T Get_Weight(unsigned int N);
    
    void Set_Input(unsigned int N, T on_Input);
    T Get_Input(unsigned int N);

    unsigned int Get_Num_Inputs();

    T Evaluate();
    bool Get_Output();

protected:
    bool (*p_Threshold_Func)(HeadNode<T>*);

    std::vector<T> Weights;
    std::vector<T> Inputs;
};

/* constructor and destructor */

template <class T>
HeadNode<T>::HeadNode()
{
}

template <class T>
HeadNode<T>::~HeadNode()
{
    Weights.clear();
    Inputs.clear();
}

/* public member functions */

template <class T>
void HeadNode<T>::Add_Input(T in_Input, T in_Weight)
{
    Inputs.push_back(in_Input);
    Weights.push_back(in_Weight);
}

template <class T>
void HeadNode<T>::Remove_Input(unsigned int N)
{
    Inputs.erase(Inputs.begin() + N);
    Weights.erase(Weights.begin() + N);
}

template <class T>
void HeadNode<T>::Set_Threshold_Func(bool (*in_p_Threshold_Func)(HeadNode<T>*))
{
    p_Threshold_Func = in_p_Threshold_Func;
}

template <class T>
void HeadNode<T>::Set_Weight(unsigned int N, T in_Weight)
{
    Weights[N] = in_Weight;
}

template <class T>
T HeadNode<T>::Get_Weight(unsigned int N)
{
    return Weights[N];
}

template <class T>
void HeadNode<T>::Set_Input(unsigned int N, T in_Input)
{
    Inputs[N] = in_Input;
}

template <class T>
T HeadNode<T>::Get_Input(unsigned int N)
{
    return Inputs[N];
}

template <class T>
unsigned int HeadNode<T>::Get_Num_Inputs()
{
    unsigned int Inputs_Size = Inputs.size();
    unsigned int Weights_Size = Weights.size();

    if (Inputs_Size == Weights_Size)
        return Inputs_Size;
    else
        return -1;
}

template <class T>
T HeadNode<T>::Evaluate()
{
    unsigned int Inputs_Size = Inputs.size();
    T Sum_So_Far = 0;

    for (unsigned int i = 0; i < Inputs_Size; i++)
    {
        Sum_So_Far += (Inputs[i] * Weights[i]);
    }

    return Sum_So_Far;
}

template <class T>
bool HeadNode<T>::Get_Output()
{
    return (*p_Threshold_Func)(this);
}

#endif /* HEADNODE_H_ */

